home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / RevRdist Folder / RevRdist / RevRdist src / copyfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  14.1 KB  |  599 lines  |  [TEXT/KAHL]

  1. /*
  2.  * copyfile.c - routines to copy a file from server to client
  3.  */
  4. #include "RevRdist.h"
  5. #include "dispatch.h"
  6. #include "desktop.h"
  7.  
  8. static Longint lastflush = 0;
  9. static void    updateSpace(void);
  10.  
  11. /*
  12.  * Methods for copying file from server to client
  13.  */
  14. typedef enum copy_method
  15. {
  16.      CP_NEW_FILE        /* no existing client file--just copy */
  17.     ,CP_BURN_BRIDGE        /* delete existing file before copy */
  18.     ,CP_RENAME            /* copy to temp file, then rename */
  19.     ,CP_EXCHANGE        /* copy to temp file, then exchange catalog entries */
  20. } copy_method_e;
  21.  
  22. #define    CLSIZE(n)    ((n + ClientClpM) & ~ClientClpM)
  23.  
  24. /*
  25.  *=========================================================================
  26.  * copyFile (sp, cp, name) - copy file from server to client
  27.  * entry:    first param = pointer to catalog list node for server file
  28.  *            second param = pointer to catalog list node for client file
  29.  *                the information here is updated if the copy succeeds.
  30.  *            third param = name of client folder to get file
  31.  *=========================================================================
  32.  */
  33. DISPATCHED (copyFile)
  34. {
  35. #define    COPYBUFSZ        65536
  36.     struct    lm
  37.     {
  38.         frame_t            f;
  39.         cnode_t *        sp;            /* copy of first arg */
  40.         cnode_t *        cp;            /* copy of second arg */
  41.         StringPtr        dname;        /* copy of third arg */
  42.         Ptr                bufp;        /* ptr to I/O buffer */
  43.         StringPtr        fn;            /* file name used */
  44.         Boolean            quit;        /* quit when copy complete */
  45.         copy_method_e    meth;        /* copy method to use */
  46.         HParamBlockRec    src;        /* param block for reading */
  47.         HParamBlockRec    dst;        /* param block for writing */
  48.     };
  49.     typedef struct lm    lm_t;
  50.     register lm_t *        m;
  51.     Ptr                    bufp;        /* temp copy of lm.bufp */
  52.     OSErr                error;
  53.     Longint                cl, sl;        /* client, server byte counts */
  54.     StringPtr            fn;            /* temp ptr to file name */
  55.     copy_method_e        meth;        /* local copy of lm.meth */
  56.     short                result;        /* our return value */
  57.     Integer                temp;
  58.     Ptr                    paramv[1];    /* return value vector */
  59.     CInfoPBRec            cb;            /* get/setCatInfo param block */
  60.     Str255                cbuf;        /* buffer for numeric conversions */
  61.     HParamBlockRec        tmp;        /* for temp file manipulations */
  62.  
  63.     m = *(lm_t **)fh;
  64.     result = request;
  65.     error = 0;
  66.     switch (request)
  67.     {
  68.     case R_INIT:
  69.         if (ClueID = resizeFrame (fh, sizeof (lm_t)))
  70.             return R_ERROR;
  71.         if ((bufp = NewPtr (COPYBUFSZ)) == nil)
  72.         {
  73.             if ((ClueID = MemError()) == 0)
  74.                 ClueID = memFullErr;
  75.             return R_ERROR;
  76.         }
  77.         m = *(lm_t **)fh;
  78.         m->sp = (cnode_t *)argv[0];
  79.         m->cp = (cnode_t *)argv[1];
  80.         m->dname = (StringPtr)argv[2];
  81.         m->bufp = bufp;
  82.         m->f.state = 1;
  83.         return R_CONT;
  84.  
  85.     case R_CONT:
  86.         /*
  87.          * Handle only the first step of R_CONT here, and the rest after
  88.          * the request switch.
  89.          */
  90.         if (m->f.state == 1)
  91.         {
  92.             sl = m->sp->in.f.fileLen + m->sp->in.f.rsrcLen;
  93.             NumToString (sl, cbuf);
  94.             notice (L_COPYING, cbuf, m->sp->name, m->dname, nil);
  95.             m->f.state = 2;
  96.             /*
  97.              * First, if there is no space, and cannot be space, give up.
  98.              * Next, determine which copy method to use.
  99.              */
  100.             sl = CLSIZE(m->sp->in.f.fileLen) + CLSIZE(m->sp->in.f.rsrcLen);
  101.             if (sl >= ClientSp)
  102.                 updateSpace();
  103.             if (sl >= ClientSp)
  104.             {
  105.                 cl = CLSIZE(m->cp->in.f.fileLen) + CLSIZE(m->cp->in.f.rsrcLen);
  106.                 if (sl >= ClientSp + cl)
  107.                 {
  108.                     error = dskFulErr;
  109.                     Clue1 = "\pupdateSpace";
  110.                     goto syserrexit;
  111.                 }
  112.                 /*
  113.                  * Must delete client file before copy
  114.                  */
  115.                 meth = CP_BURN_BRIDGE;
  116.             }
  117.             else
  118.             {
  119.                 if (!m->cp->dirID)
  120.                     meth = CP_NEW_FILE;
  121.                 else
  122.                 {
  123.                     if (ClientVIB.vMAttrib & (1<<bHasFileIDs))
  124.                         meth = CP_EXCHANGE;
  125.                     else
  126.                         meth = CP_RENAME;
  127.                 }
  128.             }
  129.             m->meth = meth;
  130.             return R_CONT;
  131.         }
  132.         break;
  133.  
  134.     case R_BACKOUT:
  135.     case R_QUIT:
  136.         goto cleanexit;
  137.     }
  138.  
  139.     /*
  140.      * The body of the R_CONT code:
  141.      */
  142.     if (Flags & PF_LISTONLY)
  143.         goto cleanexit;
  144.     /*
  145.      * Honor quit only if we are not the startup application, so that
  146.      * we don't leave files missing if an antsy student cancels
  147.      * an automatic RevRdist.
  148.      */
  149.     if (Quit)
  150.     {
  151.         Quit = false;
  152.         if (Flags & PF_STARTUP)
  153.             m->quit = true;
  154.         else
  155.             warning (E_DOQUIT, nil);    /* ask if okay to continue */
  156.     }
  157.     if (Quit)
  158.         goto cleanexit;
  159.     switch (m->f.state)
  160.     {
  161.     case 2:
  162.         /*
  163.          * open the source file on the server.
  164.          * We open either the data or resource fork.
  165.          * Only if that succeeds, create the client destination file.
  166.          */
  167.         m->src.fileParam.ioNamePtr = m->sp->name;
  168.         m->src.fileParam.ioVRefNum = ServerVol;
  169.         m->src.ioParam.ioPermssn = fsRdPerm;
  170.         m->src.fileParam.ioDirID = m->sp->parID;
  171.         if (m->sp->in.f.fileLen)
  172.             error = PBHOpen (&m->src, false);
  173.         else if (m->sp->in.f.rsrcLen)
  174.             error = PBHOpenRF (&m->src, false);
  175.         else
  176.             error = 0;
  177.         if (error)
  178.         {
  179.             if (error == fnfErr)
  180.             {
  181.                 notice (L_MISSING, m->sp->name, nil);
  182.                 goto cleanexit;
  183.             }
  184.             Clue1 = "\pPBHOpen";
  185.             goto syserrexit;
  186.         }
  187.         /*
  188.          * Do method-dependent pre-copy setup and set file name
  189.          */
  190.         switch (m->meth)
  191.         {
  192.         case CP_NEW_FILE:
  193.             fn = m->cp->name;                /* copy directly to file */
  194.             break;
  195.         case CP_BURN_BRIDGE:
  196.             if (m->cp->dirID)
  197.             {
  198.                 /*
  199.                  * If the file already exists, delete it
  200.                  */
  201.                 error = discard (m->cp, false);
  202.                 if (error)
  203.                 {
  204.                     ClueID = error;
  205.                     if (error == fBsyErr)
  206.                         notice (L_FILE, "\pdiscard", m->cp->name, nil);
  207.                     else
  208.                         warning (E_FILE, "\pdiscard", m->cp->name, nil);
  209.                     goto cleanexit;
  210.                 }
  211.             }
  212.             fn = m->cp->name;                /* copy directly */
  213.             break;
  214.         case CP_RENAME:
  215.         case CP_EXCHANGE:
  216.             fn = TempName;                    /* use temp file */
  217.             break;
  218.         }
  219.         m->fn = fn;
  220.         m->dst.fileParam.ioNamePtr = fn;
  221.         m->dst.fileParam.ioVRefNum = ClientVol;
  222.         m->dst.fileParam.ioDirID = m->cp->parID;
  223.         error = PBHCreate (&m->dst, false);
  224.         if (error)
  225.         {
  226.             ClueID = error;
  227.             warning (E_FILE, "\pcopyfile PBHCreate", fn, nil);
  228.             goto cleanexit;
  229.         }
  230.         /*
  231.          * Set file creator and type so we can get rid of it
  232.          * easily if something goes wrong.  Ignore errors.
  233.          */
  234.         error = PBHGetFInfo (&m->dst, false);
  235.         if (error == 0)
  236.         {
  237.             m->dst.fileParam.ioDirID = m->cp->parID;
  238.             m->dst.fileParam.ioFlFndrInfo.fdType = TYPE_TEMP;
  239.             m->dst.fileParam.ioFlFndrInfo.fdCreator = CREATOR;
  240.             error = PBHSetFInfo (&m->dst, false);
  241.         }
  242.         /*
  243.          * If the file has a data fork, set up to copy it.
  244.          */
  245.         if ((sl = m->sp->in.f.fileLen))
  246.         {
  247.             m->dst.ioParam.ioPermssn = fsRdWrPerm;
  248.             error = PBHOpen (&m->dst, false);
  249.             if (error)
  250.             {
  251.                 Clue1 = "\pPBHOpen";
  252.                 goto syserrexit;
  253.             }
  254.             /*
  255.              * Reduce fragmentation by allocating contiguously
  256.              */
  257.             m->dst.ioParam.ioReqCount = sl;
  258.             error = PBAllocContig ((ParmBlkPtr)&m->dst, false);
  259.             m->f.state = 3;
  260.         }
  261.         else
  262.             m->f.state = 4;                    /* skip data fork copy */
  263.         break;
  264.  
  265.     case 3:
  266.     case 5:
  267.         /*
  268.          * copy one fork in COPYBUFSZ chunks
  269.          */
  270.         m->src.ioParam.ioBuffer = m->bufp;
  271.         m->src.ioParam.ioReqCount = COPYBUFSZ;
  272.         m->src.ioParam.ioActCount = 0;
  273.         m->src.ioParam.ioPosMode = fsAtMark;
  274.         error = PBRead ((ParmBlkPtr)&m->src, false);
  275.         if ((sl = m->src.ioParam.ioActCount) != 0)
  276.         {
  277.             m->dst.ioParam.ioBuffer = m->bufp;
  278.             do
  279.             {
  280.                 m->dst.ioParam.ioReqCount = sl;
  281.                 m->dst.ioParam.ioActCount = 0;
  282.                 m->dst.ioParam.ioPosMode = fsAtMark;
  283.                 error = PBWrite ((ParmBlkPtr)&m->dst, false);
  284.                 if (error)
  285.                     break;
  286.                 sl -= m->dst.ioParam.ioActCount;
  287.                 m->dst.ioParam.ioBuffer += m->dst.ioParam.ioActCount;
  288.             } while (sl > 0);
  289.             if (error)
  290.             {
  291.                 Clue1 = "\pPBWrite";
  292.                 goto syserrexit;
  293.             }
  294.         }
  295.         else if (error && error != eofErr)
  296.         {
  297.             Clue1 = "\pPBRead";
  298.             goto syserrexit;
  299.         }
  300.         else if (error == eofErr)
  301.         {
  302.             /*
  303.              * one fork copy complete.
  304.              */
  305.             (void) PBClose ((ParmBlkPtr)&m->src, false);
  306.             m->src.ioParam.ioRefNum = 0;
  307.             error = PBClose ((ParmBlkPtr)&m->dst, false);
  308.             m->dst.ioParam.ioRefNum = 0;
  309.             if (error)
  310.             {
  311.                 Clue1 = "\pPBClose";
  312.                 goto syserrexit;
  313.             }
  314.             m->f.state++;
  315.         }
  316.         break;
  317.  
  318.     case 4:
  319.         /*
  320.          * set up to copy resource fork
  321.          * open source and destination forks
  322.          */
  323.         if ((sl = m->sp->in.f.rsrcLen) == 0)
  324.         {
  325.             m->f.state = 6;
  326.             break;
  327.         }
  328.         /*
  329.          * Open the src resource fork if we didn't do so in state 2
  330.          */
  331.         if (m->src.ioParam.ioRefNum == 0)
  332.         {
  333.             ZERO (m->src);
  334.             m->src.fileParam.ioNamePtr = m->sp->name;
  335.             m->src.fileParam.ioVRefNum = ServerVol;
  336.             m->src.ioParam.ioPermssn = fsRdPerm;
  337.             m->src.fileParam.ioDirID = m->sp->parID;
  338.             error = PBHOpenRF (&m->src, false);
  339.             if (error)
  340.             {
  341.                 Clue1 = "\pPBHOpenRF";
  342.                 goto syserrexit;
  343.             }
  344.         }
  345.         ZERO (m->dst);
  346.         m->dst.fileParam.ioNamePtr = m->fn;
  347.         m->dst.fileParam.ioVRefNum = ClientVol;
  348.         m->dst.ioParam.ioPermssn = fsRdWrPerm;
  349.         m->dst.fileParam.ioDirID = m->cp->parID;
  350.         error = PBHOpenRF (&m->dst, false);
  351.         if (error)
  352.         {
  353.             Clue1 = "\pPBHOpenRF";
  354.             goto syserrexit;
  355.         }
  356.         m->dst.ioParam.ioReqCount = sl;
  357.         error = PBAllocContig ((ParmBlkPtr)&m->dst, false);
  358.         m->f.state++;
  359.         break;
  360.  
  361.     case 6:
  362.         /*
  363.          * Both forks copied, do post-copy, method-dependent cleanup
  364.          */
  365.         switch (m->meth)
  366.         {
  367.         case CP_NEW_FILE:
  368.             cl = 0;
  369.             break;
  370.         case CP_BURN_BRIDGE:
  371.             cl = 0;                /* discard has already adjusted */
  372.             break;
  373.         case CP_EXCHANGE:
  374.         case CP_RENAME:
  375.             if (m->cp->attrib & fLocked)
  376.                 error = unlock (m->cp);
  377.             if (m->meth == CP_EXCHANGE)
  378.             {
  379.                 m->dst.fidParam.ioSrcDirID = m->cp->parID;
  380.                 m->dst.fidParam.ioDestNamePtr = m->cp->name;
  381.                 m->dst.fidParam.ioDestDirID = m->cp->parID;
  382.                 error = PBExchangeFiles (&m->dst, false);
  383.                 if (error == 0)
  384.                 {
  385.                     fn = m->fn;
  386.                     goto purge_temp;
  387.                 }
  388.                 if (error != paramErr)
  389.                 {
  390.                     Clue1 = "\pPBExchangeFiles";
  391.                     goto syserrexit;
  392.                 }
  393.                 /* Exchange unsupported, try rename */
  394.             }
  395.             /*
  396.              * First, rename the old file to a safe name
  397.              */
  398.             fn = TempName2;
  399.             for (temp = 0; temp < 2; temp++)
  400.             {
  401.                 ZERO(tmp);
  402.                 tmp.fileParam.ioNamePtr = m->cp->name;
  403.                 tmp.fileParam.ioVRefNum = ClientVol;
  404.                 tmp.fileParam.ioDirID = m->cp->parID;
  405.                 tmp.ioParam.ioMisc = (Ptr)fn;
  406.                 error = PBHRename (&tmp, false);
  407.                 if (temp == 0 && error == dupFNErr)
  408.                 {
  409.                     tmp.fileParam.ioNamePtr = fn;
  410.                     tmp.ioParam.ioMisc = 0;
  411.                     error = PBHDelete (&tmp, false);
  412.                     continue;
  413.                 }
  414.                 break;
  415.             }
  416.             Clue1 = "\pPBHRename";
  417.             if (error)
  418.                 goto syserrexit;
  419.             /*
  420.              * Now, rename the new copy to the right name
  421.              */
  422.             m->dst.fileParam.ioNamePtr = m->fn;
  423.             m->dst.fileParam.ioDirID = m->cp->parID;
  424.             m->dst.ioParam.ioMisc = (Ptr)m->cp->name;
  425.             error = PBHRename (&m->dst, false);
  426.             if (error)
  427.             {
  428.                 ZERO(tmp);
  429.                 tmp.fileParam.ioNamePtr = TempName2;
  430.                 tmp.fileParam.ioVRefNum = ClientVol;
  431.                 tmp.fileParam.ioDirID = m->cp->parID;
  432.                 tmp.ioParam.ioMisc = (Ptr)m->cp->name;
  433.                 (void) PBHRename (&tmp, false);
  434.                 goto syserrexit;
  435.             }
  436.         purge_temp:
  437.             /*
  438.              * Last, delete the renamed old copy
  439.              */
  440.             ZERO(tmp);
  441.             tmp.fileParam.ioNamePtr = fn;
  442.             tmp.fileParam.ioVRefNum = ClientVol;
  443.             tmp.fileParam.ioDirID = m->cp->parID;
  444.             error = PBHDelete (&tmp, false);
  445.             Clue1 = "\pPBHDelete";
  446.             if (error == fBsyErr)
  447.             {
  448.                 cnode_t        tnode;
  449.                 
  450.                 error = getInfo(fn, ClientVol, m->cp->parID, &tnode);
  451.                 if (error)
  452.                     Clue1 = "\pgetInfo";
  453.                 else
  454.                 {
  455.                     Clue1 = "\pmoveToJunk";
  456.                     error = moveToJunk (&tnode);
  457.                 }
  458.             }
  459.             if (error)
  460.             {
  461.                 goto syserrexit;
  462.             }
  463.             cl = CLSIZE(m->cp->in.f.fileLen) + CLSIZE(m->cp->in.f.rsrcLen);
  464.             break;
  465.         }
  466.         sl = CLSIZE(m->sp->in.f.fileLen) + CLSIZE(m->sp->in.f.rsrcLen);
  467.         ClientSp = ClientSp + cl - sl;
  468.         /*
  469.          * Copy Finder information
  470.          */
  471.         ZERO (cb);
  472.         cb.hFileInfo.ioNamePtr = m->cp->name;
  473.         cb.hFileInfo.ioVRefNum = ClientVol;
  474.         cb.hFileInfo.ioDirID = m->cp->parID;
  475.         error = PBGetCatInfo (&cb, false);
  476.         if (error)
  477.         {
  478.             Clue1 = "\pPBGetCatInfo";
  479.             goto syserrexit;
  480.         }
  481.         cb.hFileInfo.ioDirID = m->cp->parID;
  482.         temp = cb.hFileInfo.ioFlFndrInfo.fdFldr;
  483.         cb.hFileInfo.ioFlFndrInfo = m->sp->in.f.finfo;
  484. //        cb.hFileInfo.ioFlFndrInfo.fdFlags &= ~0x0100;    /* clear inited bit */
  485.         /*
  486.          * If server protected, hide the client copy, because we cannot
  487.          * protect it.
  488.          */
  489.         if (m->sp->attrib & fProtect)
  490.         {
  491.             notice (L_PROTECT, m->cp->name, nil);
  492.             cb.hFileInfo.ioFlFndrInfo.fdFlags |= fInvisible;
  493.         }
  494.         cb.hFileInfo.ioFlFndrInfo.fdFldr = temp;
  495.         cb.hFileInfo.ioFlCrDat = m->sp->crDate;
  496.         cb.hFileInfo.ioFlMdDat = m->sp->mdDate;
  497.         error = PBSetCatInfo (&cb, false);
  498.         if (error)
  499.         {
  500.             Clue1 = "\pPBSetCatInfo";
  501.             goto syserrexit;
  502.         }
  503.         saveCatInfo (&cb, m->cp);
  504.                 
  505.         desktop_update (m->sp, m->cp);
  506.         /*
  507.          * Doing a Flush after every file slowed things down too much
  508.          * on lots of small files, so we flush only every so often
  509.          */
  510.         sl = TickCount ();
  511.         if (sl - lastflush > 60 * 20)
  512.         {
  513.             m->dst.fileParam.ioNamePtr = nil;
  514.             error = PBFlushVol ((ParmBlkPtr)&m->dst, false);
  515.             if (error)
  516.             {
  517.                 Clue1 = "\pPBFlushVol";
  518.                 goto syserrexit;
  519.             }
  520.             lastflush = sl;
  521.         }
  522.         goto cleanexit;
  523.     }
  524.     return result;
  525.  
  526. syserrexit:
  527.     ClueID = error;
  528.     /*
  529.      * NFS/Share returns permErr on open of file opened with exclusive
  530.      * access by someone else.  Note it and continue.
  531.      */
  532.     if (error == permErr)
  533.     {
  534.         notice (L_FILE, "\pcopyFile", m->sp->name, nil);
  535.     }
  536.     else
  537.     {
  538.         Clue2 = nil;
  539.         warning (E_SYS, "\pcopyFile", nil);
  540.     }
  541.     /*
  542.      * If the disk fills and we are running unattended, ignore the
  543.      * error so we can finish and possibly make room for next time
  544.      */
  545.     if ((Flags & PF_STARTUP) && error == dskFulErr)
  546.         Quit = false;
  547. cleanexit:
  548.     if (GetHandleSize ((Handle)fh) >= sizeof (lm_t))
  549.     {
  550.         if (m->dst.ioParam.ioRefNum)
  551.             (void) PBClose ((ParmBlkPtr)&m->dst, false);
  552.         if (m->src.ioParam.ioRefNum)
  553.             (void) PBClose ((ParmBlkPtr)&m->src, false);
  554.         if (error && m->f.state > 2)
  555.         {
  556.             fn = m->dst.fileParam.ioNamePtr;
  557.             ZERO (m->dst);
  558.             m->dst.fileParam.ioNamePtr = fn;
  559.             m->dst.fileParam.ioVRefNum = ClientVol;
  560.             m->dst.fileParam.ioDirID = m->cp->parID;
  561.             (void) PBHDelete (&m->dst, false);
  562.         }
  563.         if (m->bufp)
  564.             DisposPtr (m->bufp);
  565.     }
  566.     if (error)
  567.         updateSpace();
  568.     else
  569.         statMsgClr ();
  570.     if (m->quit)
  571.         Quit = true;
  572.     paramv[0] = (Ptr)&error;
  573.     return (popCall (result, paramv));
  574. }
  575.  
  576.  
  577.  
  578. /*
  579.  *=========================================================================
  580.  * updateSpace() - bring ClientSp variable up to date
  581.  * entry:    ClientVol set
  582.  * exit:    ClientSp updated
  583.  *=========================================================================
  584.  */
  585. static void
  586. updateSpace(void)
  587. {
  588.     OSErr                error;
  589.     HParamBlockRec        hpb;
  590.  
  591.     ZERO (hpb);
  592.     hpb.volumeParam.ioVRefNum = ClientVol;
  593.     error = PBHGetVInfo (&hpb, false);
  594.     if (error == 0)
  595.     {
  596.         ClientSp = (unsigned long)(unsigned)hpb.volumeParam.ioVFrBlk
  597.             * (unsigned)hpb.volumeParam.ioVAlBlkSiz;
  598.     }
  599. }